/**************************************************************
 * Ben Stephenson       07025656
 * Mark Renney          07019390
 * Laurie Potts         07009314
 * Michael Peeke-Vout   07014312
 *
 * CM0034 Industrial Case Project
 * Control Panel
 * messages.c
 * 28/02/2011
 * Updated - 14/03/11 
 **************************************************************/
#include <messages.h>
#include <lcd.h>
#include <string.h>

/**************************************
 ************ PRE-PROCESSOR************
 *^z***********************************/
static messageData_t messageBuff[5];
/*z^***********************************/


/**************************************
 ************* PROTOTYPES *************
 *^z***********************************/
static void packCanMsg(messageData_t, canMessage_t *);
static bool filterCanMsg(canMessage_t *);
static void extractFields(uint32_t packedMessage, messageData_t* message);
static uint32_t compactFields(messageData_t msg);
static void putLastMsg(messageData_t *);

/*z^***********************************/

//-------------------------------------------------//
//-CAN ID----------DATA A----------DATA B----------//
//-msg type +      target id       message content-//
//-target id                                       //
//-------------------------------------------------//


/**************************************
 ************* FUNCTIONS **************
 *^z***********************************/
/*************************************************
 * Function : writeMsgToCan
 * Desc     : Writes a message to the CAN bus.
 * Return   : Void
 * Params   : messageData_t *
 *^z**********************************************/
bool  writeMsgToCan
(
   messageData_t *msg
)
{
   canMessage_t   can_msg;
   bool           status = false;
   
   packCanMsg(*msg,
              &can_msg);

   putLastMsg(msg);
   status = canWrite(1, &can_msg);

   if(status)
      ledToggle(USB_CONNECT_LED);

   return status;
}
/*z^**********************************************/


/*************************************************
 * Function : readMsgFromCan
 * Desc     : Readss a message from the CAN bus.
 * Return   : int
 * Params   : messageData_t *
 *^z**********************************************/
bool readMsgFromCan
(
   messageData_t *msg
)
{
   if (canReady(1))
   {
      //interfaceLedToggle(D1_LED);
      canMessage_t can_msg;
      
      canRead(1, &can_msg);

      if (!filterCanMsg(&can_msg))
      {
         //interfaceLedToggle(D2_LED);
         msg = (messageData_t *)0;
         return NO_MSG;
      }

      extractFields(can_msg.dataA,
                    msg);

      putLastMsg(msg);

      return MSG;
   }

   return NO_MSG;
}
/*z^**********************************************/


/*************************************************
 * Function : putLastMsg
 * Desc     : Pust the last read message into the 
 *            appropriate buffer, based on the 
 *            originator.
 * Return   : Void
 * Params   : messageData_t *
 *^z**********************************************/
static void  putLastMsg
(
   messageData_t *msg
)
{
   messageBuff[msg->originatorID] = *msg;
}
/*z^**********************************************/


/*************************************************
 * Function : getLastMsg
 * Desc     : Gets the last message from the given
 *            node.
 * Return   : Void
 * Params   : messageData_t *
 *^z**********************************************/
void  getLastMsg
(
   messageData_t *msg,
   int            node
)
{
   *msg = messageBuff[node];
}
/*z^**********************************************/

/*************************************************
 * Function : packCanMsg
 * Desc     : Packs a message into a canMessage.
 * Return   : Void
 * Params   : messageData_t, canMessage_t*
 *^z**********************************************/
static void packCanMsg
(
   messageData_t      msg,
   canMessage_t  *can_msg
)
{
   // CAN IDs have to be unique
   can_msg->id    = (msg.targetID + msg.content);
    
   uint32_t packedContent = compactFields(msg);
   
   can_msg->dataA = packedContent;
   can_msg->dataB = 0;
   can_msg->len   =  sizeof(can_msg->id)
                    +sizeof(can_msg->dataA)
                    +sizeof(can_msg->dataB);

}
/*z^**********************************************/


/*************************************************
 * Function : filterCanMsg
 * Desc     : Filters out messages not intended for this
 *            node.
 * Return   : Bool
 * Params   : messageData_t
 *^z**********************************************/
static bool filterCanMsg
(
   canMessage_t      *can_msg
)
{
   // We don't want to filter out messages with an ID_ALLNODES target
   uint32_t true_ID = can_msg->id % 5;
   if ((MY_ID != true_ID) && (true_ID != ID_ALLNODES))
   {
      return false;
   }

   return true;
}
/*z^**********************************************/


/*************************************************
 * Function : extractFields
 * Desc     : Unpacks a uint32_t into a messageData_t.
 * Return   : Void
 * Params   : uint32_t
 *^z**********************************************/
static void extractFields
(
   uint32_t packedMessage,
   messageData_t* message
)
{     
   message->targetID = packedMessage >> 16;
   
   message->originatorID = packedMessage << 16;
   message->originatorID >>= 24;
   
   message->content = packedMessage << 24;
   message->content >>= 24; 
}


/*************************************************
 * Function : compactFields
 * Desc     : Unpacks a uint32_t into a messageData_t.
 * Return   : Void
 * Params   : uint32_t
 *^z**********************************************/
static uint32_t compactFields
(
   messageData_t msg
)
{
   uint32_t message = msg.content;
   message |= (msg.originatorID << 8);
   message |= (msg.targetID << 16);
   
   return message;
}


/*************************************************
 * Function : initBuff
 * Desc     : clear the message buffer
 * Return   : void
 * Params   : void
 *^z**********************************************/
void initBuff()
{
   memset(messageBuff,
          0,
          sizeof(messageBuff));
}


/*************************************************
 * Function : sendACK
 * Desc     : Send ack message
 * Return   : bool
 * Params   : uint8_t
 *^z**********************************************/
bool sendACK
(
   uint8_t reciever
)
{
  messageData_t tempMess = {reciever, MY_ID, MSG_ACKNOLEDGE};
  return writeMsgToCan(&tempMess);
}
/*z^**********************************************/
/*z^***********************************/
/******************************************* EOF *************************************************/

